home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / asm / adisv1_3.lha / src / hunks.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-14  |  16.5 KB  |  673 lines

  1. /*
  2.  * Change history
  3.  * $Log:    hunks.c,v $
  4.  * Revision 3.0  93/09/24  17:54:01  Martin_Apel
  5.  * New feature: Added extra 68040 FPU opcodes
  6.  * 
  7.  * Revision 2.3  93/07/28  23:37:15  Martin_Apel
  8.  * Bug fix: Enabled null-sized data hunks
  9.  * 
  10.  * Revision 2.2  93/07/18  22:56:00  Martin_Apel
  11.  * *** empty log message ***
  12.  * 
  13.  * Revision 2.1  93/07/11  21:38:19  Martin_Apel
  14.  * Major mod.: Jump table support tested and changed
  15.  * 
  16.  * Revision 2.0  93/07/01  11:54:04  Martin_Apel
  17.  * *** empty log message ***
  18.  * 
  19.  * Revision 1.26  93/07/01  11:40:58  Martin_Apel
  20.  * 
  21.  * Revision 1.25  93/06/19  12:09:01  Martin_Apel
  22.  * Minor mod.: On relocation info reading, the previous word is now
  23.  *             checked for JSR also, instead of for JMP only
  24.  * 
  25.  * Revision 1.24  93/06/06  13:46:43  Martin_Apel
  26.  * Minor mod.: Replaced first_pass and read_symbols by pass1, pass2, pass3
  27.  * 
  28.  * Revision 1.23  93/06/06  00:12:03  Martin_Apel
  29.  * Major mod.: Added support for library/device disassembly (option -dl)
  30.  * 
  31.  * Revision 1.22  93/06/03  20:28:10  Martin_Apel
  32.  * New feature: Added -a switch to generate comments for file offsets
  33.  * 
  34.  * Revision 1.21  93/06/03  18:32:46  Martin_Apel
  35.  * Major mod.: Rewritten part of the hunk handling routines.
  36.  *             Overlay files are now handled correctly
  37.  * Minor mod.: Remove temporary files upon exit (even with CTRL-C)
  38.  * 
  39.  */
  40.  
  41. #include <exec/types.h>
  42. #include <dos/doshunks.h>
  43. #include <stdio.h>
  44. #include <string.h>
  45. #include "defs.h"
  46.  
  47. static char rcsid [] = "$Id: hunks.c,v 3.0 93/09/24 17:54:01 Martin_Apel Exp $";
  48.  
  49. long getlong ()
  50.  
  51. {
  52. long res;
  53.  
  54. res = fgetc (in) << 24;
  55. res |= fgetc (in) << 16;
  56. res |= fgetc (in) << 8;
  57. res |= fgetc (in);
  58. f_offset += 4L;
  59. return (res);
  60. }
  61.  
  62. /*****************************************************************/
  63.  
  64. unsigned short getword ()
  65.  
  66. {
  67. unsigned short res;
  68.  
  69. res = fgetc (in) << 8;
  70. res |= fgetc (in);
  71. f_offset += 2L;
  72. return (res);
  73. }
  74.  
  75. /*****************************************************************/
  76.  
  77. BOOL readfile ()
  78.  
  79. {
  80. long hunk_type;
  81.  
  82. total_size = 0L;
  83. current_hunk = 0;
  84. f_offset = 0L;
  85. hunk_type = getlong ();
  86. if (hunk_type != HUNK_HEADER)
  87.   {
  88.   fprintf (stderr, "ERROR: File is not executable\n");
  89.   return (FALSE);
  90.   }
  91.  
  92. do
  93.   {
  94.   switch (hunk_type)
  95.     {
  96.     case HUNK_HEADER:  read_hunk_header (); break;
  97.     case HUNK_OVERLAY: read_hunk_overlay (); break;
  98.     case HUNK_BREAK:   break;                          /* Ignore BREAK hunk */
  99.     default: fprintf (stderr, "ERROR: Unknown hunk type encountered\n");
  100.              release_mem (hunk_start);
  101.              return (FALSE);
  102.     }
  103.   hunk_type = getlong ();
  104.   }
  105. while (!feof (in));
  106.  
  107. if (pass2 && try_small && a4_offset == -1 && !warning_printed)
  108.   {
  109.   a4_offset = *(hunk_start + 1) + 0x7ffe;
  110.   fprintf (stderr, "WARNING: A4 is probably not used for base register relative addressing\n");
  111.   fprintf (stderr, "         Default address of hunk 1 plus 0x7ffe is used\n");
  112.   fprintf (stderr, "         Try disassembling in large mode\n");
  113.   warning_printed = TRUE;
  114.   }
  115.  
  116. #ifdef AMIGA
  117. if (pass2 && disasm_as_lib && !ROMTagFound)
  118.   {
  119.   fprintf (stderr, "ERROR: %s is not a library or device\n", input_filename);
  120.   ExitADis ();
  121.   }
  122. #endif
  123.  
  124. if (pass3)
  125.   release_mem (hunk_start);
  126. return (TRUE);
  127. }
  128.  
  129. /*****************************************************************/
  130.  
  131. BOOL read_hunk_header ()
  132.  
  133. {
  134. long table_size,
  135.      name_size,
  136.      hunk_size,
  137.      first_hunk,
  138.      last_hunk,
  139.      hunk_type;
  140. int i;
  141.  
  142. name_size = getlong ();
  143. for (i = 0; i < name_size; i++)
  144.   getlong ();                      /* Not interested in resident libraries */
  145.  
  146. table_size = getlong ();
  147. if (hunk_start == NULL)
  148.   {
  149.   hunk_start = get_mem (3 * table_size * sizeof (long));
  150.   hunk_end = hunk_start + table_size;
  151.   hunk_offset = hunk_end + table_size;
  152.   num_hunks = table_size;
  153.   }
  154. else if (table_size > num_hunks)
  155.   {
  156.   fprintf (stderr, "ERROR: Invalid hunk structure\n");
  157.   release_mem (hunk_start);
  158.   return (FALSE);
  159.   }
  160.  
  161. first_hunk = getlong ();
  162. last_hunk = getlong ();
  163. for (i = first_hunk; i <= last_hunk; i++)
  164.   {
  165.   hunk_size = (getlong () & 0x3fffffff) * 4;
  166.   *(hunk_start + i) = total_size;
  167.   total_size += hunk_size;
  168.   *(hunk_end   + i) = total_size;
  169.   if (pass1 && verbose)
  170.     printf ("Hunk %d: Start: %lx, Length: %lx\n", i, *(hunk_start + i),
  171.              hunk_size);
  172.   }
  173.  
  174. for (i = first_hunk; i <= last_hunk; i++)
  175.   {  
  176.   /* Bit 30 means: load this hunk into chip ram,
  177.      Bit 31 means: load this hunk into fast ram.
  178.      We're not interested in this kind of information, so we mask it out */
  179.   hunk_type = getlong () & 0x3fffffff;
  180.   if (feof (in))
  181.     {
  182.     fprintf (stderr, "ERROR: Premature end in load file\n");
  183.     release_mem (hunk_start);
  184.     return (FALSE);
  185.     }
  186.  
  187.   if (pass3)
  188.     open_output_file ();
  189.  
  190. #ifdef DEBUG
  191.   printf ("Reading hunk %d, type %lx\n", current_hunk, hunk_type);
  192. #endif
  193.  
  194.   switch (hunk_type)
  195.     {
  196.     case HUNK_CODE   : if (!read_code_hunk ())
  197.                          {
  198.                          release_mem (hunk_start);
  199.                          return (FALSE);
  200.                          }
  201.                        break;
  202.     case HUNK_DATA   : if (!read_data_hunk ())
  203.                          {
  204.                          release_mem (hunk_start);
  205.                          return (FALSE);
  206.                          }
  207.                        break;
  208.     case HUNK_BSS    : if (!read_bss_hunk ())
  209.                          {
  210.                          release_mem (hunk_start);
  211.                          return (FALSE);
  212.                          }
  213.                        break;
  214.     case HUNK_END    : if (pass3)
  215.                          close_output_file ();
  216.                        return (TRUE);
  217.     default: fprintf (stderr, "ERROR: Unknown hunk type encountered\n");
  218.              release_mem (hunk_start);
  219.              return (FALSE);
  220.     }
  221.   if (pass3)
  222.     close_output_file ();
  223.   current_hunk++;
  224.   }
  225. return (TRUE);
  226. }
  227.  
  228. /*****************************************************************/
  229.  
  230. BOOL read_hunk_overlay ()
  231.  
  232. {
  233. long table_size;
  234.  
  235. table_size = getlong ();
  236. fseek (in, (table_size + 1) * 4L, SEEK_CUR);
  237. f_offset += (table_size + 1) * 4L;
  238. return (TRUE);
  239. }
  240.  
  241. /*****************************************************************/
  242.  
  243. BOOL read_code_hunk ()
  244.  
  245. {
  246. long hunk_size;
  247. unsigned short *code_seg;
  248. long type;
  249. int i;
  250. char filename_tmp [100];
  251.  
  252. if ((hunk_size = getlong ()) == 0)
  253.   {
  254.   if (getlong () == HUNK_END)
  255.     return (TRUE);
  256.   else
  257.     return (FALSE);
  258.   }
  259.  
  260. first_address = *(hunk_start + current_hunk);
  261. last_address = first_address + hunk_size * 4;
  262. *(hunk_offset + current_hunk) = f_offset;
  263.  
  264. if (!pass1)
  265.   {
  266.   /* Generate a unique filename */
  267.   strcpy (filename_tmp, TMP_FILENAME);
  268.   sprintf (filename_tmp + strlen (filename_tmp), "%lx", ¤t_address);
  269.   sprintf (filename_tmp + strlen (filename_tmp), ".%d", current_hunk);
  270.   if (!pass3)
  271.     {
  272.     if ((tmp_f = fopen (filename_tmp, "w")) == 0)
  273.       {
  274.       fprintf (stderr, "ERROR: Couldn't open temporary file\n");
  275.       return (FALSE);
  276.       }
  277.     }
  278.   else if (!disasm_quick)
  279.     {
  280.     if ((tmp_f = fopen (filename_tmp, "r")) == 0)
  281.       {
  282.       fprintf (stderr, "ERROR: Couldn't open temporary file\n");
  283.       return (FALSE);
  284.       }
  285.     }
  286.   }
  287. else
  288.   num_code_hunks++;
  289.  
  290. code_seg = get_mem (hunk_size * (4 + 4));
  291. flags = (UBYTE*)(code_seg + hunk_size * 2);
  292. for (i = 0; i < hunk_size; i++)
  293.   *((long*)flags + i) = 0L;
  294.  
  295. if (fread (code_seg, 4, hunk_size, in) != hunk_size)
  296.   {
  297.   release_mem (code_seg);
  298.   return (FALSE);
  299.   }
  300. f_offset += hunk_size * 4;
  301.  
  302. type = getlong ();
  303. while (type != HUNK_END)
  304.   {
  305.   switch (type)
  306.     { 
  307.     case HUNK_RELOC32:
  308.          read_reloc32_hunk (code_seg);
  309.          type = getlong ();
  310.          break;
  311.     case HUNK_SYMBOL:
  312.          read_symbol_hunk ();
  313.          type = getlong ();
  314.          break;
  315.     case HUNK_DREL32:
  316.     case HUNK_RELOC32SHORT:
  317.          read_reloc16_hunk (code_seg);
  318.          type = getlong ();
  319.          break;
  320.     default:
  321.          fprintf (stderr, "ERROR: Hunk end missing\n");
  322.          return (FALSE);
  323.     }
  324.   }
  325.  
  326. if (!pass1)
  327.   {
  328.   if (pass3 && !disasm_quick)
  329.     fread (flags, hunk_size, 4, tmp_f);
  330.   if (pass3)
  331.     put ("                    CSEG\n\n");
  332.  
  333. #ifdef AMIGA
  334.   if (disasm_as_lib && pass2 && !ROMTagFound)
  335.     ROMTagFound = add_lib_labels (code_seg);
  336. #endif
  337.  
  338.   disasm_code (code_seg, hunk_size * 4L);
  339.   if (!pass3 && !disasm_quick)
  340.     fwrite (flags, hunk_size, 4, tmp_f);
  341.   }
  342.  
  343. release_mem (code_seg);
  344. if (!pass1 && !disasm_quick)
  345.   {
  346.   fclose (tmp_f);
  347.   tmp_f = NULL;
  348.   if (pass3)
  349.     remove (filename_tmp);
  350.   }
  351.  
  352. if (pass3)
  353.   {
  354.   if (last_address != *(hunk_end + current_hunk))
  355.     {
  356.     first_address = current_address;
  357.     last_address = *(hunk_end + current_hunk);
  358.     disasm_bss ();
  359.     }
  360.   }
  361. return (TRUE);
  362. }
  363.  
  364. /*****************************************************************/
  365.  
  366. BOOL read_data_hunk ()
  367.  
  368. {
  369. long hunk_size;
  370. long type;
  371. long i;
  372. USHORT *data_seg;
  373.  
  374. hunk_size = getlong ();
  375.  
  376. first_address = *(hunk_start + current_hunk);
  377. last_address = first_address + hunk_size * 4;
  378. *(hunk_offset + current_hunk) = f_offset;
  379.  
  380. if (pass1)
  381.   num_data_hunks++;
  382.  
  383. if (hunk_size != 0)
  384.   {
  385.   data_seg = get_mem (hunk_size * (4 + 4));
  386.   flags = (UBYTE*)(data_seg + hunk_size * 2);
  387.   for (i = 0; i < hunk_size; i++)
  388.     *((long*)flags + i) = 0;
  389.   
  390.   if (fread (data_seg, 4, hunk_size, in) != hunk_size)
  391.     {
  392.     release_mem (data_seg);
  393.     return (FALSE);
  394.     }
  395.   f_offset += hunk_size * 4;
  396.   }
  397.  
  398. type = getlong ();
  399. while (type != HUNK_END)
  400.   {
  401.   switch (type)
  402.     {
  403.     case HUNK_RELOC32:
  404.          read_reloc32_hunk (data_seg);
  405.          type = getlong ();
  406.          break;
  407.     case HUNK_SYMBOL:
  408.          read_symbol_hunk ();
  409.          type = getlong ();
  410.          break;
  411.     case HUNK_DREL32:
  412.     case HUNK_RELOC32SHORT:
  413.          read_reloc16_hunk (data_seg);
  414.          type = getlong ();
  415.          break;
  416.     default:
  417.          fprintf (stderr, "ERROR: Hunk end missing\n");
  418.          return (FALSE);
  419.     }
  420.   }
  421.  
  422. if (pass3)
  423.   {
  424.   put ("                    DSEG\n\n");
  425.   disasm_data ((UBYTE*)data_seg, hunk_size * 4);
  426.   put ("\n");
  427.   }
  428.  
  429. if (hunk_size != 0)
  430.   release_mem (data_seg);
  431.  
  432. if (hunk_size * 4 < *(hunk_end + current_hunk) - *(hunk_start + current_hunk)
  433.     && pass3)
  434.   {
  435.   /* The uninitialized data is part of the data segment.
  436.      ==> There might be symbol information for the rest of the segment */
  437.   first_address = current_address;
  438.   last_address = *(hunk_end + current_hunk);
  439.   disasm_bss ();
  440.   }
  441.  
  442. return (TRUE);
  443. }
  444.  
  445. /*****************************************************************/
  446.  
  447. BOOL read_bss_hunk ()
  448.  
  449. {
  450. long hunk_size;
  451. long type;
  452.  
  453. if ((hunk_size = getlong () * 4) == 0)
  454.   {
  455.   if (getlong () == HUNK_END)
  456.     return (TRUE);
  457.   else
  458.     return (FALSE);
  459.   }
  460.  
  461. first_address = *(hunk_start + current_hunk);
  462. last_address = first_address + hunk_size;
  463. *(hunk_offset + current_hunk) = f_offset;
  464. current_address = first_address;
  465.  
  466. if (pass1)
  467.   num_bss_hunks++;
  468.  
  469. if (pass3)
  470.   {
  471.   put ("                    DSEG\n\n");
  472.   disasm_bss ();
  473.   }
  474.  
  475. type = getlong ();
  476. if (type == HUNK_END)
  477.   return (TRUE);
  478. else if (type == HUNK_SYMBOL)
  479.   {
  480.   read_symbol_hunk ();
  481.   type = getlong ();
  482.   if (type != HUNK_END)
  483.     {
  484.     fprintf (stderr, "ERROR: Hunk end missing\n");
  485.     return (FALSE);
  486.     }
  487.   return (TRUE);
  488.   }
  489. fprintf (stderr, "ERROR: Hunk end missing\n");
  490. return (FALSE);
  491. }
  492.  
  493. /*****************************************************************/
  494.  
  495. BOOL read_symbol_hunk ()
  496.  
  497. {
  498. long name_length;
  499. char name [100];
  500. ULONG *ptr;
  501. int i;
  502. ULONG reference;
  503.  
  504. while ((name_length = getlong ()) != 0)
  505.   {
  506.   ptr = (ULONG*)name;
  507.   for (i = 0; i < name_length; i++)
  508.     *ptr++ = getlong ();
  509.   *ptr = 0;
  510.   reference = *(hunk_start + current_hunk) + getlong (); 
  511.   if ((reference >= *(hunk_start + current_hunk)) &&
  512.        reference < *(hunk_end + current_hunk))
  513.     enter_ref (reference, name, ACC_UNKNOWN);
  514.   }
  515. return (TRUE);
  516. }
  517.  
  518. /*****************************************************************/
  519.  
  520. BOOL read_reloc32_hunk (USHORT *hunk)
  521.  
  522. {
  523. long num_offsets;
  524. long hunk_num;
  525. long address;
  526. long i;
  527. long reference;
  528. char label [100];
  529.  
  530. while ((num_offsets = getlong ()) != 0)
  531.   {
  532.   hunk_num = getlong ();      /* following is relocation info on hunk_num */
  533.   /* gather information on labels defined within this hunk */
  534.   for (i = 0; i < num_offsets; i++)
  535.     {
  536.     address = getlong ();     /* offset in current hunk */
  537.     /* patch address, so we don't have to handle equal addresses in 
  538.        different hunks */
  539.     reference = 
  540.          (*((ULONG*)(hunk + (address >> 1))) + *(hunk_start + hunk_num));
  541.  
  542.     *(flags + address) |= PERM_RELOC;
  543.     *(flags + address + 1) |= PERM_RELOC;
  544.     *(flags + address + 2) |= PERM_RELOC;
  545.     *(flags + address + 3) |= PERM_RELOC;
  546.  
  547.     if (reference >= *(hunk_start + hunk_num) &&
  548.         reference < *(hunk_end + hunk_num))
  549.       {
  550.       /* JMP or JSR opcode there ? */
  551.       if ((*(hunk + (address >> 1) - 1) == 0x4ef9) || 
  552.           (*(hunk + (address >> 1) - 1) == 0x4eb9))
  553.         enter_ref (reference, 0L, ACC_CODE);
  554.       else
  555.         enter_ref (reference, 0L, ACC_UNKNOWN);
  556.       *((ULONG*)(hunk + (address >> 1))) = reference;
  557.  
  558.       if (pass3 && !single_file && 
  559.           ((long)reference < (long)first_address || reference >= last_address) &&
  560.           !try_small)
  561.         gen_xref (reference);
  562.       }
  563.     else if (!pass1)              /* symbol hunks have been read in */
  564.       {
  565.       /* reference relative to start of hunk */
  566.       gen_label (label, *(hunk_start + hunk_num), TRUE);
  567.       strcat (label, "+");
  568.       format_ld (label + strlen (label), reference - *(hunk_start + hunk_num), TRUE);
  569.       reference = ext_enter_ref (reference, hunk_num, label, ACC_UNKNOWN);
  570.       /* The following must be explicitly entered, so we have something
  571.          to refer to */
  572.       enter_ref (*(hunk_start + hunk_num), 0L, ACC_UNKNOWN);
  573.       *((ULONG*)(hunk + (address >> 1))) = reference;
  574.       }
  575.  
  576.     if (address > 0 && pass1 && try_small &&
  577.         *(hunk + (address >> 1) - 1) == 0x49f9)        /* LEA  $xxx.L,A4 */
  578.       {
  579.       if (a4_offset != -1 && a4_offset != reference && !warning_printed)
  580.         {
  581.         fprintf (stderr, "WARNING: A4 is probably not used for base register relative addressing\n");
  582.         fprintf (stderr, "         Try disassembling in large mode\n");
  583.         warning_printed = TRUE;
  584.         }
  585.       a4_offset = reference;
  586.       }
  587.     }
  588.   }
  589. return (TRUE);
  590. }
  591.  
  592. /*****************************************************************/
  593.  
  594. BOOL read_reloc16_hunk (USHORT *hunk)
  595.  
  596. {
  597. short num_offsets;
  598. short hunk_num;
  599. long address;
  600. long i;
  601. long reference;
  602. char label [100];
  603.  
  604. while ((num_offsets = getword ()) != 0)
  605.   {
  606.   hunk_num = getword ();      /* following is relocation info on hunk_num */
  607.  
  608. #ifdef DEBUG
  609.   printf ("Reading reloc16 for hunk %d. Num_offsets = %d\n", hunk_num, num_offsets);
  610. #endif
  611.  
  612.   /* gather information on labels defined within this hunk */
  613.   for (i = 0; i < num_offsets; i++)
  614.     {
  615.     address = getword ();     /* offset in current hunk */
  616.     /* patch address, so we don't have to handle equal addresses in 
  617.        different hunks */
  618.     reference = 
  619.          (*((ULONG*)(hunk + (address >> 1))) + *(hunk_start + hunk_num));
  620.  
  621.     *(flags + address) |= PERM_RELOC;
  622.     *(flags + address + 1) |= PERM_RELOC;
  623.     *(flags + address + 2) |= PERM_RELOC;
  624.     *(flags + address + 3) |= PERM_RELOC;
  625.  
  626.     if (reference >= *(hunk_start + hunk_num) &&
  627.         reference < *(hunk_end + hunk_num))
  628.       {
  629.       /* JMP or JSR opcode there ? */
  630.       if ((*(hunk + (address >> 1) - 1) == 0x4ef9) || 
  631.           (*(hunk + (address >> 1) - 1) == 0x4eb9))
  632.         enter_ref (reference, 0L, ACC_CODE);
  633.       else
  634.         enter_ref (reference, 0L, ACC_UNKNOWN);
  635.       *((ULONG*)(hunk + (address >> 1))) = reference;
  636.  
  637.       if (pass3 && !single_file && 
  638.           ((long)reference < (long)first_address || reference >= last_address) &&
  639.           !try_small)
  640.         gen_xref (reference);
  641.       }
  642.     else if (!pass1)              /* symbol hunks have been read in */
  643.       {
  644.       /* reference relative to start of hunk */
  645.       gen_label (label, *(hunk_start + hunk_num), TRUE);
  646.       strcat (label, "+");
  647.       format_ld (label + strlen (label), reference - *(hunk_start + hunk_num), TRUE);
  648.       reference = ext_enter_ref (reference, hunk_num, label, ACC_UNKNOWN);
  649.       /* The following must be explicitly entered, so we have something
  650.          to refer to */
  651.       enter_ref (*(hunk_start + hunk_num), 0L, ACC_UNKNOWN);
  652.       *((ULONG*)(hunk + (address >> 1))) = reference;
  653.       }
  654.  
  655.     if (address > 0 && pass1 && try_small &&
  656.         *(hunk + (address >> 1) - 1) == 0x49f9)        /* LEA  $xxx.L,A4 */
  657.       {
  658.       if (a4_offset != -1 && a4_offset != reference && !warning_printed)
  659.         {
  660.         fprintf (stderr, "WARNING: A4 is probably not used for base register relative addressing\n");
  661.         fprintf (stderr, "         Try disassembling in large mode\n");
  662.         warning_printed = TRUE;
  663.         }
  664.       a4_offset = reference;
  665.       }
  666.     }
  667.   }
  668.  
  669. if ((f_offset & 0x3) != NULL)
  670.   getword ();                 /* To make it long aligned */
  671. return (TRUE);
  672. }
  673.